package main

import (
	logger "github.com/alecthomas/log4go"
	"github.com/gorilla/websocket"

	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"strings"
	"time"
)

var (
	quote_host string
)

func init() {
	flag.StringVar(&quote_host, "qh", "ws://10.15.107.138:20718/dataproxy", "ws quote host")
}

type QuoteClient struct {
	chExit   chan bool
	chReqUrl chan string
	infoChan chan *ObjInfo
}

func NewQuoteClient() *QuoteClient {
	client := new(QuoteClient)
	client.chExit = make(chan bool)
	client.chReqUrl = make(chan string, 1024)
	client.infoChan = make(chan *ObjInfo, 1024)
	return client
}

/*
{"req_seq":"148","res_seq":"1","res_type":"0","result":
	{ "head":["obj","buyprice1","buyprice2","buyprice3","buyprice4","buyprice5","buyvol1","buyvol2","buyvol3","buyvol4","buyvol5","new","sellprice1","sellprice2","sellprice3","sellprice4","sellprice5","sellvol1","sellvol2","sellvol3","sellvol4","sellvol5","time"],
	 "datas":[["SH502048.fnd",0.880000,0.879000,0.877000,0.876000,0.875000,5542.000000,500.000000,1000.000000,2880.000000,1066.000000,0.880000,0.882000,0.883000,0.884000,0.885000,0.887000,4281.000000,5500.000000,5.000000,1128.000000,160.000000,1437737396]]
	}
}
*/
func (this QuoteClient) unmarshalObjInfo(objMsg []byte) (*ObjInfo, error) {
	var mapRes map[string]interface{}
	err := json.Unmarshal(objMsg, &mapRes)
	if err != nil {
		return nil, err
	}
	res_seq := mapRes[`res_seq`].(string)
	mapRes, _ = mapRes[`result`].(map[string]interface{})
	interArr, _ := mapRes[`datas`].([]interface{})
	if len(interArr) == 0 {
		return nil, errors.New("Not Data!")
	}
	interArr, _ = interArr[0].([]interface{})
	if len(interArr) == 0 {
		return nil, errors.New("Not Data!")
	}
	idx := -1
	index := func() int { idx++; return idx }
	info := new(ObjInfo)
	info.Obj, _ = interArr[index()].(string)
	if i := strings.Index(info.Obj, "."); i != -1 {
		info.Obj = string(info.Obj[:i])
	}
	for i := 0; i < 5; i++ {
		if info.BuyFive[i] == nil {
			info.BuyFive[i] = new(PriceVol)
		}
		info.BuyFive[i].Price, _ = interArr[index()].(float64)
	}
	for i := 0; i < 5; i++ {
		info.BuyFive[i].Volume, _ = interArr[index()].(float64)
	}
	info.NewPrice, _ = interArr[index()].(float64)
	for i := 0; i < 5; i++ {
		if info.SellFive[i] == nil {
			info.SellFive[i] = new(PriceVol)
		}
		info.SellFive[i].Price, _ = interArr[index()].(float64)
	}
	for i := 0; i < 5; i++ {
		info.SellFive[i].Volume, _ = interArr[index()].(float64)
	}
	datatime, _ := interArr[index()].(float64)
	info.Time = int64(datatime) - 8*3600

	if res_seq == "1" {
		resStr, _ := json.Marshal(info)
		logger.Info("first resopnse parse_info: %s", string(resStr))
	}
	return info, nil
}

func (this *QuoteClient) start() error {
	ws, _, err := websocket.DefaultDialer.Dial(quote_host, nil)
	if err != nil {
		logger.Error("websocket connect err: %s", err)
		return err
	}
	//read
	go func() {
		defer func() {
			ws.Close()
			this.stop()
		}()
		ws.SetPingHandler(func(string) error {
			logger.Error("receive ping, and will send pong")
			ws.WriteControl(websocket.PongMessage, nil, time.Now().Add(10*time.Second))
			return nil
		})
		for {
			_, msg, err := ws.ReadMessage()
			if err != nil {
				logger.Error("wsread message error: %s", err)
				return
			}
			//1.通过请求序号判断,首条用于返回qid的响应直接跳过
			if bytes.Index(msg, []byte(`"res_seq":"0"`)) != -1 {
				continue
			}
			//2.判断data_clear_response，清盘响应直接向chan中发送nil
			if bytes.Index(msg, []byte(`"data_clear_response":"1"`)) != -1 {
				logger.Info("receive clear_data response: %s", string(msg))
				this.infoChan <- nil
				continue
			}
			//3.解析响应并将响应通过chan发送
			msg = msg[1:]
			if infoRes, err := this.unmarshalObjInfo(msg); err != nil {
				logger.Error("UnmarshalObjInfo err: %s; response(json): %s", err, string(msg))
			} else {
				this.infoChan <- infoRes
			}
		}
	}()
	//write
	go func() {
		defer func() {
			ws.WriteControl(websocket.CloseMessage, nil, time.Now().Add(3))
			ws.Close()
		}()
		for {
			select {
			case url := <-this.chReqUrl:
				logger.Info("Send WebSoketRequest: %s", url)
				err := ws.WriteMessage(websocket.TextMessage, []byte(url))
				if err != nil {
					logger.Error("ws write message error: %s", err)
					return
				}
			case <-this.chExit:
				return
			}
		}
	}()
	return nil
}

func (this *QuoteClient) sendreq(reqUrl string) {
	this.chReqUrl <- reqUrl
}

func (this *QuoteClient) reciveres() (*ObjInfo, error) {
	select {
	case res := <-this.infoChan:
		return res, nil
	case <-this.chExit:
		return nil, errors.New("exit")
	}
	return nil, nil
}

func (this *QuoteClient) stop() {
	if this.chExit != nil {
		close(this.chExit)
		this.chExit = nil
	}
}
